<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    function Person(name) {
      //  在构造函数里面，只写属性
      this.name = name;
    }
    // 方法写在构造函数的元素对象上面？
    // 1. 扩展属性时，直接让prototype指向一个全新的对象，则要修复 constructor.
    // Person.prototype = {
    //   sayHi: function () {
    //     console.log(this.name);
    //   },
    //   title: 'abc'
    // }
    // Person.prototype.constructor = Person;

    // 2. 在prototype对象上，动态添加属性的方式，则默认的 constructor 就指向构造函数本身，不需要修复。
    Person.prototype.sayHi = function () {
      console.log(this.name);
    };
    Person.prototype.age = 22;

    let a = new Person('刘小杰')
    let b = new Person('李雯艺')

    // console.log(a.sayHi === b.sayHi); // true
    // a.sayHi()
    // b.sayHi()
    // console.log(a.title); //'abc'
    // console.log(b.title); //'abc'

    // 原型：解决方法过载的问题。对类的功能进行扩展。
    // 在 JS 中，每一个函数都有一个 prototype 属性，这个属性是一个指针，指向函数的原型对象，而这个对象的所有属性和方法都可以被对应的实例共享。
    // 类名.prototype = {属性名， 方法名}
    // 类名.prototype.属性名 = 属性值
    // 类名.prototype.方法名 = function() {}
    // 原型模式最大问题在于共享的本性所导致的,由于共享,因此一个实例修改了引用,另一个也随之修改了引用。

    console.log(b)
    // 如果你给prototype赋值一个新对象，则需要修复constructor。
    // 让他重新指向自己的构造函数


    // __proto__
    // 每个实例对象（ object ）都有一个私有属性（称之为 __proto__ ）指向它的构造函数的原型对象（ prototype ）。

    /* 
    __proto__ 和prototype的区别 :
    ● __proto__ 只出现在对象上，实际上是对类的原型 prototype 属性的引用
    ● prototype 出现在构造函数的属性列表中
    */

    console.log(a.age); //22
    // 当对象访问属性的时候，如果在对象内部找不到， 那么会在原型对象中查找到属性；如果原型对象中仍然找不到属性，原型对象会查找自身的原型对象，如此循环下去，直至找到属性或者到达顶级对象。对象查找属性的过程所经过的对象构成一条链，这条链，叫做原型链。
    // 属性查找顺序：
// 对象属性 > 构造函数 > 原型链(继承)。
  </script>
</body>

</html>